﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;

namespace mapxp
{
    class Algo
    {
        private static bool print = false;
        /** This functiuon gets a point and a map and retuns true if the point 
         * is in the map
         * It will return false otherwise.
         * */
        public static Boolean isInTheMap(My_Point p, Map m)
        {
            if (p.x_value() < 0 || p.y_value() < 0) return false;
            if (p.x_value() > (m.getXSizeOfArray()-1) * m.getX0()) return false;
            if (p.y_value() > (m.getYSizeOfArray()-1) * m.getY0()) return false;
            return true;
        }
        /** This fucntion gets a point and a map and calculate the point's heigth.
         * Note - the x and y values have to be Integers!!!
         * */
        public static double calc_point_height(My_Point p, Map m)
        {
            double z = -1000000;
            if (isInTheMap(p, m))
            {//אם הנקודה לא במפה אז נחזיר מסםר נמוך מאוד
                int x = (int)p.x_value();
                int y = (int)p.y_value();
                if (x % (m.getX0()) == 0 && y % (m.getY0()) == 0)
                {
                    return m.getArray()[(int)(x / m.getX0()), (int)(y / m.getY0())];
                }
                int i = (int)(x / m.getX0());
                int j = (int)(y / m.getY0());
                if (x % m.getX0() == 0)
                {
                    double h1 = m.getArray()[i, j];
                    double h2 = m.getArray()[i, j + 1];
                    z = h1 + (y % m.getY0()) * (h2 - h1) / m.getY0();
                }
                else
                {
                    double h1 = m.getArray()[i, j];
                    double h2 = m.getArray()[i + 1, j];
                    z = h1 + (x % m.getX0()) * (h2 - h1) / m.getX0();
                }
            }
            return z;
        }
        /** This function gets a list and a point and return true if the point is in the list
         * otherwise it returns false.
         * */
        public static Boolean isIn(List<My_Point> list, My_Point p)
        {
            for (int i = 0; i < list.Count(); i++)
            {
                if (p.x_value() == list.ElementAt<My_Point>(i).x_value() && p.y_value() == list.ElementAt<My_Point>(i).y_value()) return true;
            }
            return false;
        }
        /** This function gets 2 points and a map and return a list with all the 
         * intersection points in the way.
         * Note - if one of these points isn't in the map, the list will be empty.
         * */
        public static List<My_Point> intersection(My_Point p1, My_Point p2, Map m)
        {
            List<My_Point> ans = new List<My_Point>();
            if (isInTheMap(p1, m) && isInTheMap(p2, m))
            {
                p1.set_z_value(calc_point_height(p1,m));
                p2.set_z_value(calc_point_height(p2,m));
                ans.Add(p1);
                if (!isIn(ans, p2)) ans.Add(p2);//למקרה וקיבלנו את אותה נקודה בדיוק
                if (p1.x_value() != p2.x_value())//אם קיבלנו ישר שלא מאונך לציר האיקס עושים את זה
                {
                    if (p1.x_value() > p2.x_value())
                    {//אני רוצה לבדוק מהקטן לגדול אז אם זה הפוף נחליף בין הנקודות
                        My_Point temp = new My_Point(p1.x_value(), p1.y_value(), p1.z_value());
                        p1 = p2;
                        p2 = temp;
                    }
                    if ((int)(p1.x_value()) % m.getX0() != 0)
                    {
                        for (int i = (int)Math.Min(p1.x_value() / m.getX0(), p2.x_value() / m.getX0()) + 1; i <= Math.Max(p1.x_value() / m.getX0(), p2.x_value()) / m.getX0(); i++)
                        {//לבדוק האם כשהחלפנו בין הנקודות אפשר להוריד את העניין של מינ מקס
                            double x = i * m.getX0();
                            double y = p1.y_value() + ((p2.y_value() - p1.y_value()) / (p2.x_value() - p1.x_value()) * (i * m.getX0() - p1.x_value()));
                            double z = calc_point_height(new My_Point(x, y, 0), m);
                            if (!isIn(ans, new My_Point(x, y, z))) ans.Add(new My_Point(x, y, z));
                        }
                    }
                    else
                    {
                        for (int i = (int)Math.Min(p1.x_value() / m.getX0(), p2.x_value() / m.getX0()); i <= Math.Max(p1.x_value() / m.getX0(), p2.x_value() / m.getX0()); i++)
                        {
                            double x = i * m.getX0();
                            double y = p1.y_value() + ((p2.y_value() - p1.y_value()) / (p2.x_value() - p1.x_value()) * (i * m.getX0() - p1.x_value()));
                            double z = calc_point_height(new My_Point(x, y, 0), m);
                            if (!isIn(ans, new My_Point(x, y, z))) ans.Add(new My_Point(x, y, z));
                        }
                    }
                }

                if (p1.y_value() != p2.y_value())
                {
                    if (p1.y_value() > p2.y_value())
                    {
                        My_Point temp = new My_Point(p1.x_value(), p1.y_value(), p1.z_value());
                        p1 = p2;
                        p2 = temp;
                    }
                    if ((int)(p1.y_value()) % m.getY0() != 0)
                    {
                        for (int j = (int)Math.Min(p1.y_value() / m.getY0(), p2.y_value() / m.getY0()) + 1; j <= Math.Max(p1.y_value() / m.getY0(), p2.y_value() / m.getY0()); j++)
                        {
                            double x = p1.x_value() + ((p2.x_value() - p1.x_value()) / (p2.y_value() - p1.y_value()) * ((j * m.getY0()) - p1.y_value()));
                            double y = j * m.getY0();
                            double z = calc_point_height(new My_Point(x, y, 0), m);
                            if (!isIn(ans, new My_Point(x, y, z))) ans.Add(new My_Point(x, y, z));
                        }
                    }
                    else
                    {
                        for (int j = (int)Math.Min(p1.y_value() / m.getY0(), p2.y_value() / m.getY0()); j <= Math.Max(p1.y_value() / m.getY0(), p2.y_value() / m.getY0()); j++)
                        {
                            double x = p1.x_value() + ((p2.x_value() - p1.x_value()) / (p2.y_value() - p1.y_value()) * ((j * m.getY0()) - p1.y_value()));
                            double y = j * m.getY0();
                            double z = calc_point_height(new My_Point(x, y, 0), m);
                            if (!isIn(ans, new My_Point(x, y, z))) ans.Add(new My_Point(x, y, z));
                        }
                    }
                }

                sort(ans, ans[0],m);
                //sort2(ans);

                try
                {
                    StreamWriter sw = new StreamWriter("Last_Intersection_call.txt");
                    sw.WriteLine(ans.Count());
                    for (int i = 0; i < ans.Count(); i++)
                    {
                        sw.WriteLine("(" + ans[i].x_value() + "," + ans[i].y_value() + "," + ans[i].z_value() + ")");
                    }
                    sw.Close();
                }
                catch (Exception e)
                {
                    Console.WriteLine("Exception: " + e.Message);
                }
                //finally
                //{
                //    Console.WriteLine("Executing finally block.");
                //}
            }
            return ans;
        }
        /** This functiom gets 2 points and returns the distance between them.
         * Note - it checks first if these two points are in the map
         * */
        public static double distance(My_Point a, My_Point b, Map map)
        {
            double ans = 100000000;
            if (isInTheMap(a,map) && isInTheMap(b,map))
            {
                ans = Math.Sqrt(((a.x_value() - b.x_value()) * ((a.x_value() - b.x_value())) + ((a.y_value() - b.y_value()) * (a.y_value() - b.y_value()))));
            }
            return ans;
        }
        /**Thsi function gets a list of points and a single point, and sorts the list 
         * according to the points distance from the given point
         * */
        private static void sort(List<My_Point> list, My_Point a,Map m)
        {
            My_Point[] arr = list.ToArray();
            int size = list.Count();

            My_Point[] tmp = new My_Point[size]; // make another double array as size as arr to put the number as we want.
            Q_sort(arr, tmp, 0, size, a,m); //calls the 'Q_sort' fanction.
            list.Clear();
            for (int i = 0; i < size; i++)
            {
                list.Add(arr[i]);
            }
        }
        private static void Q_sort(My_Point[] arr, My_Point[] tmp, int start, int end, My_Point a,Map m)
        {
            if (end - start < 2) return;//if the fanction working on array less then 2 cells stop!!!
            int e = end - 1, s = start;
            My_Point pivot = arr[start];//pivor is the number witch will be in the center of the ended array
            for (int i = start + 1; i < end; i++)
            {
                double len1 = distance(a, arr[i],m);
                double len2 = distance(a, pivot,m);
                if (len1 <= len2)
                {//cell who get smaller number then pivot goes to the start of the new array 
                    tmp[s] = arr[i]; s = s + 1;//raise 's' to put the next smaller number in the 'next cell'.
                }
                else
                {//cell who get bigger number then pivot goes to the end of the new array
                    tmp[e] = arr[i]; e = e - 1;//lower 'e' to put the next bigger number in the 'previous cell'.
                }
            }
            tmp[s] = pivot;//put the pivot in the center of the new array
            for (int i = start; i < end; i++)
            {
                arr[i] = tmp[i];
            }//copy the new array to the array we started with    
            Q_sort(arr, tmp, start, s, a,m);//call to the faunction itself to sort the number that smaller than the pivot (again and again) - Recursion
            Q_sort(arr, tmp, e + 1, end, a,m);//call to the faunction itself to sort the number that bigger than the pivot (again and again) - Recursion
        }
        /** This function gets 2 points and relative heights and returns true if these two
         * points can see each other.
         * */
        public static Boolean can_see(My_Point p1, double height_p1, My_Point p2, double height_p2, Map m)
        {
            bool ans = true;
            if (isInTheMap(p1,m) && isInTheMap(p2,m))
            {
                My_Point p_1 = new My_Point(p1.x_value(), p1.y_value(), p1.z_value() + height_p1);
                My_Point p_2 = new My_Point(p2.x_value(), p2.y_value(), p2.z_value() + height_p2);
                List<My_Point> l = intersection(p_1, p_2, m);
                double x0 = p_1.x_value();
                double y0 = p_1.y_value();
                double z0 = p_1.z_value();
                double x1 = p_2.x_value();
                double y1 = p_2.y_value();
                double z1 = p_2.z_value();
                if (z0 == z1)
                {
                    for (int i = 1; i < l.Count(); i++)
                    {
                        double Ztemp = l[i].z_value();
                        if (Ztemp - z0 >0.00000001) return false;

                    }
                }
                else
                {
                    for (int i = 1; i < l.Count(); i++)
                    {
                        double Xtemp = l[i].x_value();
                        double Ytemp = l[i].y_value();
                        double Ztemp = l[i].z_value();
                        if (Ztemp - (((z0 - z1) / (x0 - x1)) * (Xtemp - x0) + z0) > 0.00000001)
                        {
                            if (print) Console.WriteLine(" i " + i + " z " + Ztemp + " calcX " + (((z0 - z1) / (x0 - x1)) * (Xtemp - x0) + z0));
                            return false;
                        }
                        if (Ztemp - (((z0 - z1) / (y0 - y1)) * (Ytemp - y0) + z0) > 0.0000000001)
                        {
                            if (print) Console.WriteLine(" i " + i + " z " + Ztemp + " calcY " + (((z0 - z1) / (y0 - y1)) * (Ytemp - y0) + z0));
                            return false;
                        }
                    }
                }        
            }
            return ans;
        }

        public static Boolean can_see_ark(My_Point p1, double height_p1, My_Point p2, double height_p2, Map m) {

            List<My_Point> l = intersection(p1, p2, m);
            double first_angle = (p2.z_value() - p1.z_value() + height_p2 - height_p1) / distance(p1, p2, m);

            double angle_tmp = 0;
            int counter = 0;
            while (counter < l.Count)
            {
                angle_tmp = (l[counter].z_value() - p1.z_value() - height_p1) / distance(l[counter], p1, m);
                if (print) Console.WriteLine("counter " + counter + " first_angle " + first_angle + " angle_tmp " + angle_tmp);
                if (angle_tmp > first_angle) { return false; }
                counter++;
            }

            return true;
        
        }

        /**
         * מחזירה את כל הנקודות שניתן לראות מנקודה נתונה עם מרחק ראייה נתון
         * */
        public static List<My_Point> circule_seen_points(My_Point p, double height_p, double R, Map m)
        {
            List<My_Point> ans = new List<My_Point>();
            double x0 = p.x_value();
            double y0 = p.y_value();
            int xOnCirclePlus = (int)((x0 + R) / m.getX0());//הגדרת ערכי 'איקס' של קצות המעגל שבניהם נחפש את ערכי המאות
            int xOnCircleMinus = 0;
            if ((int)(x0 - R) % m.getX0() == 0)
            {
                xOnCircleMinus = (int)((x0 - R) / m.getX0());
            }
            else
            {
                if (x0 - R < 0) xOnCircleMinus = 0;
                else xOnCircleMinus=(int)((x0-R)/m.getX0())+1;
            }
            for (int i = xOnCircleMinus; i <= xOnCirclePlus; i++)
            {
                int x1=(int)(i*m.getX0());
                if (isInTheMap(new My_Point(x1,0,0), m))
                {
                    double y1 = Math.Sqrt((R * R) - (x1 - x0) * (x1 - x0)) + y0;
                    double y2 = (-1) * Math.Sqrt((R * R) - (x1 - x0) * (x1 - x0)) + y0;
                    if (y1>(m.getYSizeOfArray()-1)*m.getY0())y1=(m.getYSizeOfArray()-1)*m.getY0();
                    if (y2<0)y2=0;
                    if (y1!=y2||((int)y1%m.getY0()==0&&(int)y2%m.getY0()==0))
                    {
                        if ((int)y2%m.getY0()==0)
                        {
                            for (int y=(int)(y2/m.getY0());y<=(int)(y1/m.getY0());y++)
                            {
                                if (y*m.getY0()<y2)y++;
                                My_Point temp=new My_Point(x1,y*m.getY0(),0);
                                temp.set_z_value(calc_point_height(temp,m));
                               if (can_see_ark(p,height_p,temp,0,m))
                               {
                                   if (!isIn(ans,temp))ans.Add(temp);
                               }
                            }
                        } 
                        else
                        {
                            for (int y=(int)(y2/m.getY0())+1;y<=(int)(y1/m.getY0());y++)
                            {
                                if (y*m.getY0()<y2)y++;
                                My_Point temp=new My_Point(x1,y*m.getY0(),0);
                                temp.set_z_value(calc_point_height(temp,m));
                                if (can_see_ark(p,height_p,temp,0,m))
                                {
                                    if (!isIn(ans,temp))ans.Add(temp);
                                }
                            }
                        }
                    }
                }
            }
            return ans;
        }
        /**This fucntion gets 2 points and relative heights and returns the seen-way from 
         * point a to point b.
         * */
        public static List<My_Point> Find_Way(My_Point p1, double height_p1, My_Point p2, double height_p2, double R, Map m)
        {
            return Find_Way2(p1, height_p1, p2, height_p2, R, R, m, new Random(1234));
            /**List<My_Point> ans = new List<My_Point>();
            My_Point p_1 = new My_Point(p1.x_value(), p1.y_value(), (p1.z_value() + height_p1));
            ans.Add(new My_Point(p_1.x_value(),p_1.y_value(),p_1.z_value()));//מכניסים את הנקודת התחלה עם הגובה היחסי ששינינו בשורה הקודמת
            while (p_1.x_value() != p2.x_value() || p_1.y_value() != p2.y_value() || p_1.z_value() != p2.z_value())//זה אומר שעדיין לא הגענו לנקודת הסיום
            {
                List<My_Point> v = circule_seen_points(p_1, 0, R, m);
                for (int i = 0; i < v.Count(); i++)
                {
                    double d1 = distance(v[i], p2,m);
                    double d2 = distance(p_1, p2,m);
                    if (d1 < d2)//נחליף בין הנקודות אלא אם כן מדובר בנקודה הסופית שאותה יש לבדוק עם גובה יחסי
                    {
                        if (v[i].x_value()!=p2.x_value()||v[i].y_value()!=p2.y_value()||v[i].z_value()!=p2.z_value())
                        {
                            p_1.set_x_value(v[i].x_value());
                            p_1.set_y_value(v[i].y_value());
                            p_1.set_z_value(v[i].z_value());
                        }
                        else break;
                    }
                }
                if (!isIn(ans, p_1)) ans.Add(new My_Point(p_1.x_value(), p_1.y_value(), p_1.z_value()));
                else break;
            }
            if (can_see_ark(p_1,0,p2,height_p2,m))
            {
                p_1.set_x_value(p2.x_value());
                p_1.set_y_value(p2.y_value());
                p_1.set_z_value(p2.z_value()+height_p2);
                ans.Add(p_1);
            }                        
            return ans;
            */
        }
        public static List<My_Point> Find_Way2(My_Point p1, double height_p1, My_Point p2, double height_p2, double R, double OriginalR, Map m, Random r)
        {
            List<My_Point> ans = new List<My_Point>();
            My_Point p_1 = new My_Point(p1.x_value(), p1.y_value(), (p1.z_value() + height_p1));
            My_Point p_2 = new My_Point(p2.x_value(), p2.y_value(), (p2.z_value() + height_p2));

            if (distance(p_1, p_2,m) <= OriginalR)
            {
                if (can_see(p_1, 0, p_2, 0, m))
                {
                    ans.Add(p_1);
                    ans.Add(p_2);
                    return ans;
                }
            }

            Boolean swich = false;
            if (p_2.x_value() < p_1.x_value())//ע"מ שלפחות כלפי ציר ה-איקס תמיד תהיה בעליה בסוף התהליך נמיין את הנקודות הגבוהות בסדר הפוך בגלל המשתנה הבוליאני
            {
                My_Point temp = new My_Point(p_1.x_value(), p_1.y_value(), p_1.z_value());
                p_1 = p_2;
                p_2 = temp;
                swich = true;
            }
            List<My_Point> highest = gethighestsInRectangle(p_1, p_2, R, m);
            
            if (swich)
            {

                My_Point temp = new My_Point(p_1.x_value(), p_1.y_value(), p_1.z_value());
                p_1 = p_2;
                p_2 = temp;
            }
            ans.Add(p_1);
            int index = r.Next(0, highest.Count);
            List<My_Point> tmp1 = Find_Way2(p_1, 0, highest[index], 0, R / 2, OriginalR, m, r);
            List<My_Point> tmp2 = Find_Way2(highest[index], 0, p_2, 0, R / 2, OriginalR, m, r);
            for (int i = 0; i < tmp1.Count; i++)
            {
                if (!isIn(ans, tmp1[i])) ans.Add(tmp1[i]);
            }
            for (int i = 1; i < tmp2.Count; i++)
            {
                if (!isIn(ans, tmp2[i])) ans.Add(tmp2[i]);
            }
            if (!isIn(ans, p_2)) ans.Add(p_2);
            if (swich)//אם החלפנו את הנקודות בגלל ערכי האיקס שלהם אז נמיין את רשימת הגבהים לפי הנקודה הראשונה האמיתית
            //וכך אנו נקבל את הדרך מנקודה א לנקודה ב ולא להיפך
            {
                sort(ans, p_1,m);
            }

            return ans;
        }
        //מחזירה את כל הגבוהים בתוך המלבן שנוצר משתי הנקודות הנתונות
        private static List<My_Point> gethighestsInRectangle(My_Point p_1, My_Point p_2, Double R, Map m)
        {
            if (R < m.getX0()) R = m.getX0();//כדי שבודאות יהיה נקודות גבוהות על הצירים
            List<My_Point> highest = new List<My_Point>();//לכאן נכניס את הנקודה הגבוהה ביותר בכל ריבוע
            if (p_1.x_value() == p_2.x_value() || p_1.y_value() == p_2.y_value())//אם הנקודות נמצאות על אותו ישר א"א לחלק לריבועים אלא לקטעים על הישר
            {

                if (R / 2 > m.getX0()) R = R / 2;// מקטינים שוב את הרדיוס כי בחלוקה לקטעים מוסיפים כל פעם את הרדיוס ואנו לא רוצים להיכנס ללולאה אין סופית
                else R = m.getX0();

                if (p_1.y_value() == p_2.y_value())
                {
                    int lastXstop = (int)(p_1.x_value());
                    int Xstop = (int)(lastXstop + R);
                    while (lastXstop < p_2.x_value())
                    {
                        double max = 0;
                        int i1 = lastXstop;
                        int j = (int)p_2.y_value();
                        for (int i = lastXstop; i <= Xstop && i <= p_2.x_value(); i++)
                        {
                            if (max < m.getArray()[i, j])
                            {
                                max = m.getArray()[i, j];
                                i1 = i;
                            }
                        }
                        My_Point temp = new My_Point(i1 * m.getX0(), j * m.getY0(), max);
                        if (!isIn(highest, temp)) highest.Add(temp);
                        lastXstop = Xstop;
                        Xstop = (int)(lastXstop + R);
                    }
                }
                else
                {
                    int lastYstop = (int)(p_1.y_value());
                    int sign = 1;
                    if (p_1.y_value() > p_2.y_value()) sign = -1;
                    if (sign == 1)//כלומר אנו עולים בערכי ה-וואי
                    {
                        int Ystop = (int)(lastYstop + sign * (R));
                        while (lastYstop < p_2.y_value())
                        {
                            double max = 0;
                            int i = (int)p_1.x_value();
                            int j1 = lastYstop;
                            for (int j = lastYstop; j <= Ystop && j <= p_2.y_value(); j++)
                            {
                                if (max < m.getArray()[i, j])
                                {
                                    max = m.getArray()[i, j];
                                    j1 = j;
                                }
                            }
                            My_Point temp = new My_Point(i * m.getX0(), j1 * m.getY0(), max);
                            if (!isIn(highest, temp)) highest.Add(temp);
                            lastYstop = Ystop;
                            Ystop = (int)(lastYstop + R);

                        }
                    }
                    else  //כלומר אנו יורדים בערכי ה-וואי
                    {
                        int Ystop = (int)(lastYstop + sign * (R /*/ Math.Sqrt(5)*/));
                        while (lastYstop > p_2.y_value())
                        {
                            double max = 0;
                            int i = (int)p_1.x_value();
                            int j1 = lastYstop;
                            for (int j = lastYstop; j >= Ystop && j >= p_2.y_value(); j--)
                            {
                                if (max < m.getArray()[i, j])
                                {
                                    max = m.getArray()[i, j];
                                    j1 = j;
                                }
                            }
                            My_Point temp = new My_Point(i * m.getX0(), j1 * m.getY0(), max);
                            if (!isIn(highest, temp)) highest.Add(temp);
                            lastYstop = Ystop;
                            Ystop = (int)(lastYstop - R);
                        }
                    }
                }
            }
            else  //אם הנקודות יוצרות מלבן נחלק אותו לריבועים
            {
                int lastXstop = (int)(p_1.x_value());
                int Xstop = (int)(lastXstop + (R / Math.Sqrt(5)));
                while (lastXstop < p_2.x_value())
                {
                    int lastYstop = (int)(p_1.y_value());
                    int sign = 1;
                    if (p_1.y_value() > p_2.y_value()) sign = -1;

                    if (sign == 1)// כלומר אנו עולים בערכי ה-וואי
                    {
                        int Ystop = (int)(lastYstop + sign * (R /*/ Math.Sqrt(5)*/));
                        while (lastYstop < p_2.y_value())
                        {
                            double max = 0;
                            int i1 = lastXstop;
                            int j1 = lastYstop;
                            for (int i = lastXstop; i <= Xstop && i <= p_2.x_value(); i++)
                            {
                                for (int j = lastYstop; j <= Ystop && j <= p_2.y_value(); j++)
                                {
                                    if (max < m.getArray()[i, j])
                                    {
                                        max = m.getArray()[i, j];
                                        i1 = i;
                                        j1 = j;
                                    }

                                }
                            }
                            My_Point temp = new My_Point(i1 * m.getX0(), j1 * m.getY0(), max);
                            if (!isIn(highest, temp)) highest.Add(temp);
                            lastYstop = Ystop;
                            Ystop = (int)(lastYstop + sign * (R /*/ Math.Sqrt(5)*/));

                        }//end while Y
                    }
                    else  //כלומר אנו יורדים בערכי ה-וואי
                    {
                        int Ystop = (int)(lastYstop + sign * (R /*/ Math.Sqrt(5)*/)) + 1;
                        while (lastYstop > p_2.y_value())
                        {
                            double max = 0;
                            int i1 = lastXstop;
                            int j1 = lastYstop;
                            for (int i = lastXstop; i <= Xstop && i <= p_2.x_value(); i++)
                            {
                                for (int j = lastYstop; j >= Ystop && j >= p_2.y_value(); j--)
                                {
                                    if (max < m.getArray()[i, j])
                                    {
                                        max = m.getArray()[i, j];
                                        i1 = i;
                                        j1 = j;
                                    }

                                }
                            }
                            My_Point temp = new My_Point(i1 * m.getX0(), j1 * m.getY0(), max);
                            if (!isIn(highest, temp)) highest.Add(temp);
                            lastYstop = Ystop;
                            Ystop = (int)(lastYstop + sign * (R /*/ Math.Sqrt(5)*/)) + 1;

                        }//end while Y
                    }
                    lastXstop = Xstop;
                    Xstop = (int)(lastXstop + (R /*/ Math.Sqrt(5)*/));
                }//end while X
            }
            return highest;
        }

	
    }//end of Class Algo
}//end of namespace mapxp
